{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33d58df4-edd4-4289-b3ee-6bc783de31a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install transformers accelerate pandas tqdm\n",
    "\n",
    "\n",
    "#Step 1. Load Model\n",
    "from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline\n",
    "import torch\n",
    "\n",
    "model_name = \"meta-llama/Llama-3-8b-hf\"  \n",
    "\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_name)\n",
    "model = AutoModelForCausalLM.from_pretrained(\n",
    "    model_name,\n",
    "    torch_dtype=torch.float16,\n",
    "    device_map=\"auto\"\n",
    ")\n",
    "\n",
    "generator = pipeline(\"text-generation\", model=model, tokenizer=tokenizer, max_new_tokens=100)\n",
    "\n",
    "#Step 2. Define Korean Prompt\n",
    "def build_prompt_korean_continuous(article_text, candidate_name):\n",
    "    return f\"\"\"\n",
    "당신은 정치 뉴스 감성 분석가입니다. 아래 뉴스 기사가 후보자 \"{candidate_name}\"에 대해 어떤 감정적 태도를 보이는지 분석하십시오.\n",
    "\n",
    "기사:\n",
    "\\\"{article_text.strip()}\\\"\n",
    "분석 항목:\n",
    "1. 감정 극성(Valence): 기사 전반에 나타난 후보자에 대한 평가를 0(매우 부정적)에서 1(매우 긍정적) 사이의 숫자로 정량화하십시오.\n",
    "2. 정서 강도(Arousal): 감정 표현의 강도를 0(감정이 거의 없음)에서 1(감정이 매우 강함) 사이의 숫자로 정량화하십시오.\n",
    "\n",
    "다음과 같은 형식으로 응답하십시오:\n",
    "감정 극성: [0.0 - 1.0]\n",
    "정서 강도: [0.0 - 1.0]\n",
    "\"\"\"\n",
    "\n",
    "#Step 3. Inference & Parcing Logic\n",
    "def parse_response_continuous(text):\n",
    "    valence, arousal = None, None\n",
    "    for line in text.split('\\n'):\n",
    "        if '감정 극성' in line:\n",
    "            try:\n",
    "                valence = float(line.split(\":\")[1].strip())\n",
    "            except:\n",
    "                valence = None\n",
    "        elif '정서 강도' in line:\n",
    "            try:\n",
    "                arousal = float(line.split(\":\")[1].strip())\n",
    "            except:\n",
    "                arousal = None\n",
    "    return valence, arousal\n",
    "\n",
    "#Step 4. Batch Processing Function\n",
    "from tqdm import tqdm\n",
    "import pandas as pd\n",
    "\n",
    "def classify_articles_continuous(df, article_col='article', candidate_col='candidate'):\n",
    "    results = []\n",
    "    for _, row in tqdm(df.iterrows(), total=len(df)):\n",
    "        article = row[article_col]\n",
    "        candidate = row[candidate_col]\n",
    "        prompt = build_prompt_korean_continuous(article, candidate)\n",
    "        output = generator(prompt)[0]['generated_text']\n",
    "        valence, arousal = parse_response_continuous(output)\n",
    "        \n",
    "        results.append({\n",
    "            'candidate': candidate,\n",
    "            'article': article,\n",
    "            'valence': valence,\n",
    "            'arousal': arousal\n",
    "        })\n",
    "    return pd.DataFrame(results) \n",
    "\n",
    "#Step 5. Load and Run\n",
    "df = pd.read_csv(\"full_articles.csv\")  # 144,000 articles\n",
    "results_df = classify_articles(df)\n",
    "\n",
    "# Save to disk\n",
    "results_df.to_csv(\"llama3_sentiment_results.csv\", index=False)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f98944d4-68ce-493c-b85f-a8df746671e7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
